#include "GeometryShaderSample.h"
#include "IObject.h"


GeometryShaderSample::GeometryShaderSample(MeshTypeData mt)
{
	Sshader = new GeoShader(MeshTypeData::PositionTextureNormal);
	//Sshader->Init("effect.fx","VS","vs_4_0","PS","ps_4_0",*InputLayouts::GetVertexLayout(MeshTypeData::PositionTextureNormal));
	Init("phongtess.fx","VSGS","vs_4_0",NULL,NULL,*InputLayouts::GetVertexLayout(MeshTypeData::PositionTextureNormal),"GSTESS","gs_4_0");
	firstTime = true;
}

GeometryShaderSample::~GeometryShaderSample(void)
{	
}

HRESULT GeometryShaderSample::Init(const char* effectName,const char* VsName, const char* vsVersion, const char* PsName,const char* psVersion, VertexLayout vl, const char* GsName ,const char* GsVersion , D3D11_SO_DECLARATION_ENTRY declaration[] , int nElements ,UINT* stride , UINT numStrides)
{
	D3D11_SO_DECLARATION_ENTRY soDeclaration[] = 
	{
		{ 0, "POSITION", 0, 0, 3, 0 },		
		{ 0, "TEXCOORD", 0, 0, 2, 0 },
		{ 0, "NORMAL", 0, 0, 3, 0 },
	};
	
	///create and compile shaders
	HRESULT hr = S_OK;
	UINT strides[1];
	strides[0] = sizeof(float) * 8;
	SOstride = strides[0];
	hr = IShader::Init(effectName,VsName,vsVersion,PsName,psVersion,vl,GsName,GsVersion,soDeclaration,3,strides,1);
	CheckError(hr);

	///create SO buffer	
	int m_nBufferSize = 100000000;
	D3D11_BUFFER_DESC bufferDesc =
	{
		m_nBufferSize,
		D3D11_USAGE_DEFAULT,
		D3D11_BIND_STREAM_OUTPUT | D3D11_BIND_VERTEX_BUFFER,
		0,
		0
	};
	hr = EngineStuff::EGraphicsDevice->CreateBuffer( &bufferDesc, NULL, &g_SOBuffer);
	CheckError(hr);
	
	hr = EngineStuff::EGraphicsDevice->CreateBuffer( &bufferDesc, NULL, &auxBuffer);
	CheckError(hr);	

	D3D11_RASTERIZER_DESC rasterizerState;
	rasterizerState.FillMode = D3D11_FILL_SOLID;
	rasterizerState.CullMode = D3D11_CULL_NONE;
    rasterizerState.FrontCounterClockwise = false;
    rasterizerState.DepthBias = false;
    rasterizerState.DepthBiasClamp = 0;
    rasterizerState.SlopeScaledDepthBias = 0;
    rasterizerState.DepthClipEnable = true;
    rasterizerState.ScissorEnable = false;
    rasterizerState.MultisampleEnable = false;
    rasterizerState.AntialiasedLineEnable = true;
	hr = EngineStuff::EGraphicsDevice->CreateRasterizerState( &rasterizerState, &g_RasterState );
	CheckError(hr);

	D3D11_DEPTH_STENCIL_DESC descDS;
	ZeroMemory(&descDS, sizeof(descDS));
	descDS.DepthEnable = false;
	descDS.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO;	
	descDS.StencilEnable = false;	
	hr = EngineStuff::EGraphicsDevice->CreateDepthStencilState( &descDS, &g_DepthState);
	CheckError(hr);

	return hr;
}
void GeometryShaderSample::SetShaderOnDevice(RenderableObject obj)
{	
	if(firstTime)
	{
		EngineStuff::PushRasterState(g_RasterState);
		EngineStuff::PushDepthState(g_DepthState,1);
		
		IShader::SetShaderOnDevice(obj);	
		obj.IOBJECT->GetMesh()->SetMeshOnDevice();

		for(int i = 0 ; i < 5 ; i++) ///ja ta muito (controla a "recursao" eh explosivo, a cada iteracao o numero de triangulos cresce 3x)
		{
			UINT offset[1];
			offset[0] = 0;
			
			if(i % 2 == 0)
			{
				ID3D11Buffer* buff[1] = { auxBuffer };		
				EngineStuff::EImediateDeviceContext->SOSetTargets( 1, buff, offset );
			}
			else
			{
				ID3D11Buffer* buff[1] = { g_SOBuffer };		
				EngineStuff::EImediateDeviceContext->SOSetTargets( 1, buff, offset );
			}												
			
			obj.IOBJECT->GetMesh()->DrawMesh();

			ID3D11Buffer* nullbuffer[1] = { NULL };		
			EngineStuff::EImediateDeviceContext->SOSetTargets( 1, nullbuffer, offset );		


			if(i % 2 == 0)
			{
				obj.IOBJECT->GetMesh()->SetVertexBuffer(auxBuffer,0,SOstride );
			}
			else
			{
				obj.IOBJECT->GetMesh()->SetVertexBuffer(g_SOBuffer,0,SOstride );
			}

			obj.IOBJECT->GetMesh()->SetIndexBuffer(NULL,0);						
			obj.IOBJECT->GetMesh()->SetMeshOnDevice();
		}
		
		firstTime = false;

		EngineStuff::PopRasterState();
		EngineStuff::PopDepthState();
	}

	Sshader->SetShaderOnDevice(obj);
}
void GeometryShaderSample::UnsetShaderOnDevice(RenderableObject obj) 
{
	Sshader->UnsetShaderOnDevice(obj);	
}

void GeometryShaderSample::Update(RenderableObject obj,Camera* camera)
{		
	Sshader->Update(obj,camera);
}
